/*!
    \file    main.c
    \brief   main

    \version  demo for GD32F30x
*/


#include "gd32f30x.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "ZDT_X42_V2.h"
#include "cli_shell.h"
#include "dbg_config.h"
#include "z_test.h"

#define DBG_TAG "STD"
#define DBG_LVL DBG_LOG
#include <dbg_print.h>
#if SEGGER_RTT_OUTPUT_PRINT_EN
//static uint8_t segger_buff[BUFFER_SIZE_UP];
#endif


void gd_debug_com_init(void);
void gd_uart3_init(uint32_t baud);
void gd_uart1_init(uint32_t baud);
/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
    uint32_t count = 0;

    // 定义接收数据数组、接收数据长度
    uint8_t rxCmd[128] = {0}; uint8_t rxCount = 0;

    static uint32_t time_1s;
    static uint32_t time_100ms;
    static uint32_t time_10ms;
    static struct motor_state state;


    /* initialize the LEDs */
    //led_init();
    SystemInit();
    /* configure systick */
    systick_config();

    #if SEGGER_RTT_OUTPUT_PRINT_EN
    //SEGGER_RTT_Init();
    //SEGGER_RTT_ConfigUpBuffer(0, "RTT", segger_buff, BUFFER_SIZE_UP, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
    #endif
    /* flash the LEDs for 1 time */
    //led_flash(1);

    /* debug com */
    //gd_debug_com_init();
    //gd_uart3_init(115200);
    gd_uart1_init(115200);
    usart_init();



    /* output a message on hyperterminal using printf function */
    printf("\r\n USART printf example: please press the Tamper key \r\n");

    /* wait for completion of USART transmission */
    usart_data_transmit(UART3, (uint8_t)0X55);
    //while(RESET == usart_flag_get(UART3, USART_FLAG_TC)){
    //}
    /* enable the led clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    /* configure led GPIO port */ 
    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_7);

    GPIO_BOP(GPIOA) = GPIO_PIN_7; 
    //ZDT_X42_V2_En_Control(1,1,0);
    //ZDT_X42_V2_Receive_Data(rxCmd, &rxCount);

    //ZDT_X42_V2_Velocity_Control(1,0,100,100.0,0);
    //ZDT_X42_V2_Receive_Data(rxCmd, &rxCount);

    // 直通限速位置模式：转速2000RPM，相对位置运动-3600.0°
    //ZDT_X42_V2_Bypass_Position_LV_Control(1, 1, 2000.0f, 3600.0f, 0, 0);

    // 等待返回命令，命令数据缓存在数组rxCmd上，长度为rxCount
    //ZDT_X42_V2_Receive_Data(rxCmd, &rxCount);

    // 验证校验字节
    //if(rxCmd[rxCount - 1] == 0x6B) { } else { }
    cli_call_init(); // 使用rtt的命令行

    time_1s = systick_get();  // 1000HZ的时钟频率 开始计时 ， 
    time_100ms = time_1s;
    time_10ms = time_100ms;
    LOG_I("Z_TEST START...");
		//初始化LEDgpio
    tst_z_test_init();
		// 开始启动电机
    tst_z_move_start();
//    void x_test_init(void);
    //x_test_init();
    while(1)
    {
        if ((systick_get() - time_10ms) >= 10) // 每10ms调用一次
        {
            time_10ms = systick_get();
            cli_polling_entry();
            tst_z_move_task();
        }
    }
}


void gd_debug_com_init(void)
{
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_UART4);

    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_GPIOD);

    /* connect port to USARTx_Tx */
    gpio_init(GPIOC, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);

    /* connect port to USARTx_Rx */
    gpio_init(GPIOD, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_2);

    /* USART configure */
    usart_deinit(UART4);
    usart_baudrate_set(UART4, 115200U);
    usart_receive_config(UART4, USART_RECEIVE_ENABLE);
    usart_transmit_config(UART4, USART_TRANSMIT_ENABLE);
    usart_enable(UART4);
}

void gd_uart3_init(uint32_t baud)
{
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOC);

    /* enable USART clock */
    rcu_periph_clock_enable(RCU_UART3);
    
    /* connect port to USARTx_Tx */
    gpio_init(GPIOC, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

    /* connect port to USARTx_Rx */
    gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_11);

    /* configure USART */
    usart_deinit(UART3);
    usart_baudrate_set(UART3, baud);
    usart_transmit_config(UART3, USART_TRANSMIT_ENABLE);
    usart_receive_config(UART3, USART_RECEIVE_ENABLE);
    //usart_dma_receive_config(UART3, USART_RECEIVE_DMA_ENABLE);
    usart_enable(UART3);
#if 0
    /*Enable rcv and transmit*/
    usart_interrupt_enable(UART3,USART_INT_RBNE);
    //usart_interrupt_enable(UART3,USART_INT_TBE);
    
    
    
    /* USART interrupt configuration */
    NVIC_SetPriorityGrouping(1);
    NVIC_SetPriority(UART3_IRQn,1);
    NVIC_EnableIRQ(UART3_IRQn);
#endif
}

void gd_uart1_init(uint32_t baud)
{
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);

    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART1);
    
    /* connect port to USARTx_Tx */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);

    /* connect port to USARTx_Rx */
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_3);

    /* configure USART */
    usart_deinit(USART1);
    usart_baudrate_set(USART1, baud);
    usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
    usart_receive_config(USART1, USART_RECEIVE_ENABLE);
    //usart_dma_receive_config(UART3, USART_RECEIVE_DMA_ENABLE);
    usart_enable(USART1);
#if 0
    /*Enable rcv and transmit*/
    usart_interrupt_enable(USART1,USART_INT_RBNE);
    usart_interrupt_enable(USART1,USART_INT_IDLE);
    //usart_interrupt_enable(UART3,USART_INT_TBE);
    
    
    
    /* USART interrupt configuration */
    NVIC_SetPriorityGrouping(1);
    NVIC_SetPriority(USART1_IRQn,1);
    NVIC_EnableIRQ(USART1_IRQn);
#endif
}
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
    #if 0
    usart_data_transmit(UART4, (uint8_t)ch);
    //usart_data_transmit(UART3, (uint8_t)ch);
    while(RESET == usart_flag_get(UART4, USART_FLAG_TBE));
    #endif
    #if 1
    usart_data_transmit(USART1, (uint8_t)ch);
    while(RESET == usart_flag_get(USART1, USART_FLAG_TBE));
    #endif
    return ch;
}


#define FLASH_PAGE_SIZE    (0x800) // 2KB
/**
 * @brief for gd32 bank 0 flash, any one of the page size is 2KB
 */
static void flash_earse_pages(uint32_t page_addr, uint16_t page_num)
{
    /* unlock the flash program/erase controller */
    fmc_unlock();

    /* clear all pending flags */
    fmc_flag_clear(FMC_FLAG_BANK0_END);
    fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
    fmc_flag_clear(FMC_FLAG_BANK0_PGERR);

    /* erase the flash pages */
    for (int16_t idx = 0; idx < page_num; idx++)
    {
        fmc_page_erase(page_addr + (FLASH_PAGE_SIZE * idx));
        fmc_flag_clear(FMC_FLAG_BANK0_END);
        fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
        fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
    }

    /* lock the main FMC after the erase operation */
    fmc_lock();
}

/**
 * @brief for gd32 bank 0 flash, any one of the page size is 2KB
 */
static void flash_earse_page(uint32_t page_addr)
{
    /* unlock the flash program/erase controller */
    fmc_unlock();

    /* clear all pending flags */
    fmc_flag_clear(FMC_FLAG_BANK0_END);
    fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
    fmc_flag_clear(FMC_FLAG_BANK0_PGERR);

    fmc_page_erase(page_addr);

    /* lock the main FMC after the erase operation */
    fmc_lock();
}

static void flash_write_word(uint32_t address, uint32_t data)
{
    /* unlock the flash program/erase controller */
    fmc_unlock();

    fmc_state_enum ret = fmc_word_program(address, data);
    if (ret != FMC_READY)
    {
        //rt_kprintf("fmc_word_program fail. ret = %d, data = 0x%x\n", ret, data);
    }

    /* lock the main FMC after the program operation */
    fmc_lock();
}

static inline uint32_t flash_read_word(uint32_t address)
{
    return REG32(address);
}

#define TEST_FLASH_ADDR     0x0803f000
static int flash_opt(int argc, char **argv)
{
    uint32_t val;

    if (argc > 1)
    {
        if (!strcmp(argv[1], "get"))
        {
            val = flash_read_word(TEST_FLASH_ADDR);
            LOG_D("flash addr:%x,val:%d", TEST_FLASH_ADDR, val);
        }
        else if (!strcmp(argv[1], "set"))
        {
            val = atoi(argv[2]);
            //gd32_flash_earse_pages(TEST_FLASH_ADDR,1);
            flash_write_word(TEST_FLASH_ADDR,val);
        }
        else if (!strcmp(argv[1], "erase"))
        {
            val = atoi(argv[2]);
            flash_earse_page(TEST_FLASH_ADDR);
            //flash_write_word(TEST_FLASH_ADDR,val);
        }
    }
    return 0;
}
CLI_CMD_EXPORT(flash_opt, flash_opt [get/set] [value]);